﻿#[derive(Debug, Default)]
pub enum Token {
    DoSym,      // do
    ElseSym,    //else  
    IfSym,      // if
    WhileSym,   // while
    Lbra,       // {
    Rbra,       // }
    Lpar,       // (
    Rpar,       // )
    Plus,       // +
    Minus,      // -
    Less,       // <
    Semi,       // ;
    Equal,      // =
    Int(isize), // 整数常量
    Id(String), // 标识符
    #[default] // 如果没有匹配到任何一个, 则默认匹配到这个
    Eoi, // 结束标记
}

impl Token {
    pub(crate) fn new() -> Token {
        Token::default()
    }
}
#[derive(Clone, Debug)]
pub struct Lexer<'a> {
    /// 从源中为我们提供 chars 的可窥视迭代器
    chars_iter: std::iter::Peekable<std::str::Chars<'a>>, //一个迭代器，其中 a peek() 返回对下一个元素的可选引用。
    // 可速览字符的源代码位置
    curr_pos: SourcePosition,
}

impl<'a> Lexer<'a> {
    pub(crate) fn new(str: &str) -> Lexer {
        Lexer {
            chars_iter: str.chars().peekable(), //创建一个迭代器，该迭代器可以使用 peek and peek_mut 方法查看迭代器的下一个元素，
            curr_pos: SourcePosition { line: 1, column: 1 }, //初始化当前位置
        }
    }
    pub fn syntax_error(&self, msg: SourcePosition, pos: &str) { 
        let msg = format!(
            "Syntax error at line {} column {}: {}",
            msg.line, msg.column, pos
        );
        std::io::Error::new(std::io::ErrorKind::InvalidInput, msg);
        std::process::exit(1)
    }
    pub fn next_char(&mut self) {
        self.chars_iter.next();
        self.curr_pos.column += 1;
        if self.current_char() == '\n' {
            self.curr_pos.line += 1;
            self.curr_pos.column = 1;
        }
    }
    pub fn current_char(&mut self) -> char {
        *self.chars_iter.peek().unwrap_or(&'\0') //返回迭代器的下一个元素，如果没有下一个元素则返回 '\0'
    }
    pub fn get_current_token(&mut self) -> (SourcePosition, Token) {
        while self.current_char().is_whitespace()
            || self.current_char().is_control()
            || self.current_char() == '#'
        {
            self.next_char();
        }
        let position = self.curr_pos;
        let token = match self.current_char() {
            '\0' => Token::Eoi,
            '{' => Token::Lbra,
            '}' => Token::Rbra,
            '(' => Token::Lpar,
            ')' => Token::Rpar,
            '+' => Token::Plus,
            '-' => Token::Minus,
            '<' => Token::Less,
            ';' => Token::Semi,
            '=' => Token::Equal,
            '0'..='9' => {
                let mut num_str = String::new();
                num_str.push(self.current_char());
                self.next_char();
                while let Some(c) = self.current_char().to_digit(10) {
                    num_str.push(self.current_char());
                    self.next_char();
                }
                 return ( position, Token::Int(num_str.parse().unwrap() )) ; 
            }
            'a'..='z' | 'A'..='Z' | '_' => {
                let mut id_str = String::new();
                id_str.push(self.current_char());
                self.next_char();
                while self.current_char().is_ascii_lowercase()
                    || self.current_char().is_ascii_uppercase()
                {
                    id_str.push(self.current_char());
                    self.next_char();
                }
                return ( position, match id_str.as_str() {
                    "do" => Token::DoSym,
                    "else" => Token::ElseSym,
                    "if" => Token::IfSym,
                    "while" => Token::WhileSym,
                    _ => Token::Id(id_str),
                }) ; 
            }

            _ => {
                self.syntax_error(position ,"Invalid character" );
                Token::Eoi
            }
        };  
        self.next_char(); // 读取下一个字符 
        (position, token)
    }
}
#[derive(Clone, Copy, Default, Debug)]
pub struct SourcePosition {
    pub line: usize,   // 行号
    pub column: usize, // 列号
}

 
